package dao

import (
	"encoding/json"
	"fmt"
	"github.com/go-resty/resty/v2"
	"github.com/spf13/viper"
	"time"
	"yundian/internel/app/helper"
	"yundian/internel/app/helper/request"
	"yundian/internel/app/helper/resphelper/placeresp"
	"yundian/internel/app/models/placemodel"
	"yundian/internel/pkg/dingo"
	"yundian/internel/pkg/dingo/global"
)

type LogisticsDao struct {
}

type ThirdLogisticsInfo struct {
	Code int `json:"code"`
	Data struct {
		Status        string `json:"status"`
		LogisticsList []struct {
			Time    string `json:"time"`
			Context string `json:"context"`
		} `json:"logisticsList"`
	} `json:"data"`
}

func NewLogisticsDao() *LogisticsDao {
	return &LogisticsDao{}
}

// 获取第三方物流详情
func (d *LogisticsDao) GetThirdLogisticsInfo(param *placemodel.PlaceLogisticsModel) *dingo.ErrorWrap {
	mobile := param.MailPhone
	if mobile == "" && param.ReceivePhone != "" {
		mobile = param.ReceivePhone
	}

	url := viper.GetString("logistics.url")
	appCode := viper.GetString("logistics.appcode")
	postData := map[string]string{
		"expressCode": "auto",
		"mobile":      mobile,
		"number":      param.LogisticsOrderNo,
	}
	client := resty.New()
	resp, err := client.R().SetFormData(postData).SetHeader("Content-Type", "application/x-www-form-urlencoded").
		SetHeader("Authorization", "APPCODE "+appCode).Post(url)
	if err != nil {
		return dingo.ErrorIf(err, "")
	}

	var thirdLogisticsInfoData ThirdLogisticsInfo
	json.Unmarshal([]byte(string(resp.Body())), &thirdLogisticsInfoData)
	return dingo.ErrorIf(nil, thirdLogisticsInfoData, string(resp.Body()))
}

// 获取网点物流详情
func (d *LogisticsDao) GetPlaceLogisticsInfo(param *placemodel.PlaceLogisticsModel) *dingo.ErrorWrap {
	logisticsInfo := &placemodel.PlaceLogisticsModel{}
	db := global.Orm.Debug().Table("logistics")
	if db.Where("id=? AND logistics_order_no=?", param.Id, param.LogisticsOrderNo).First(&logisticsInfo); db.Error != nil {
		return dingo.ErrorIf(db.Error, nil)
	}

	if logisticsInfo.Id > 0 && logisticsInfo.Status == helper.TypeNumLogisticsStatusReceived {
		var thirdLogisticsInfoData ThirdLogisticsInfo
		json.Unmarshal([]byte(logisticsInfo.LogisticsInfo), &thirdLogisticsInfoData)
		return dingo.ErrorIf(db.Error, thirdLogisticsInfoData.Data)
	}

	LogisticsInfo := d.GetThirdLogisticsInfo(logisticsInfo)
	LogisticsInfoData := LogisticsInfo.Unwrap().(ThirdLogisticsInfo)
	LogisticsInfoStr := LogisticsInfo.Val().(string)

	d.UpdateLogisticsInfoToDb(param.Id, LogisticsInfoStr, LogisticsInfoData)

	return dingo.ErrorIf(db.Error, LogisticsInfoData.Data)
}

// 获取网点物流详情
func (d *LogisticsDao) GetPlaceLogisticsInfoNotSelectDb(param *placemodel.PlaceLogisticsModel) *dingo.ErrorWrap {

	LogisticsInfo := d.GetThirdLogisticsInfo(param)
	LogisticsInfoData := LogisticsInfo.Unwrap().(ThirdLogisticsInfo)
	LogisticsInfoStr := LogisticsInfo.Val().(string)

	d.UpdateLogisticsInfoToDb(param.Id, LogisticsInfoStr, LogisticsInfoData)
	return dingo.ErrorIf(nil, LogisticsInfoData)
}

// 更新物流信息
func (d *LogisticsDao) UpdateLogisticsInfoToDb(id int, LogisticsInfoStr string, LogisticsInfoData ThirdLogisticsInfo) *dingo.ErrorWrap {
	if LogisticsInfoData.Code == 200 {
		d := map[string]interface{}{
			"status": LogisticsInfoData.Data.Status,
		}
		if LogisticsInfoStr != "" {
			d["logistics_info"] = LogisticsInfoStr
		}
		if LogisticsInfoData.Data.Status == fmt.Sprintf("%d", helper.TypeNumLogisticsStatusReceived) {
			if len(LogisticsInfoData.Data.LogisticsList) > 0 {
				d["receive_time"] = LogisticsInfoData.Data.LogisticsList[0].Time
			}
		}
		db := global.Orm.Debug().Table("logistics").Where("id=?", id).Updates(d)
		return dingo.ErrorIf(db.Error, true)
	}
	return dingo.ErrorIf(nil, true)
}

// 新增网点物流
func (d *LogisticsDao) InsertPlaceLogisticsInfo(param *placemodel.PlaceLogisticsModel) *dingo.ErrorWrap {
	create := map[string]interface{}{
		"status":             0,
		"logistics_info":     "",
		"place_id":           param.PlaceId,
		"mail_phone":         param.MailPhone,
		"receive_phone":      param.ReceivePhone,
		"logistics_order_no": param.LogisticsOrderNo,
	}
	db := global.Orm.Debug().Table("logistics").Create(create)
	return dingo.ErrorIf(db.Error, true)
}

// 批量新增网点物流
func (d *LogisticsDao) BatchInsertPlaceLogisticsInfo(param []*placemodel.PlaceLogisticsModel) *dingo.ErrorWrap {
	createList := []map[string]interface{}{}

	for _, item := range param {
		createList = append(createList, map[string]interface{}{
			"status":             0,
			"logistics_info":     "",
			"place_id":           item.PlaceId,
			"mail_phone":         item.MailPhone,
			"receive_phone":      item.ReceivePhone,
			"logistics_order_no": item.LogisticsOrderNo,
		})
	}

	db := global.Orm.Debug().Table("logistics").Create(createList)
	return dingo.ErrorIf(db.Error, true)
}

// 根据酒店ID 查询网点ID
func (d *LogisticsDao) GetPlaceIdsInHotel(param []string, placeIds []int) *dingo.ErrorWrap {
	var placeLst []*placemodel.PlaceModel
	db := global.Orm.Debug().Table("places").Select("hotel_id,id").
		Where("(hotel_id in ? or id in ?)", param, placeIds).Find(&placeLst)

	return dingo.ErrorIf(db.Error, placeLst)
}

// 修改网点物流
func (d *LogisticsDao) UpdatePlaceLogisticsInfo(param *placemodel.PlaceLogisticsModel) *dingo.ErrorWrap {

	update := map[string]interface{}{
		"place_id":           param.PlaceId,
		"mail_phone":         param.MailPhone,
		"receive_phone":      param.ReceivePhone,
		"logistics_order_no": param.LogisticsOrderNo,
		"return_status":      param.ReturnStatus,
		"message":            param.Message,
	}
	//退回状态为是时，添加退回时间
	if param.ReturnStatus == 1 {
		update["return_time"] = time.Now().Format("2006-01-02 15:04:05")
	}

	db := global.Orm.Debug().Table("logistics").Where("id=?", param.Id).Updates(update)
	return dingo.ErrorIf(db.Error, true)
}

// 删除网点物流
func (d *LogisticsDao) DeletePlaceLogistics(param *placemodel.PlaceLogisticsModel) *dingo.ErrorWrap {
	db := global.Orm.Exec("DELETE FROM logistics WHERE id=?", param.Id)
	return dingo.ErrorIf(db.Error, db.Error == nil)
}

// 查询网点物流
func (d *LogisticsDao) GetPlaceLogisticsList(param *request.PlaceLogisticsModelListReq) *dingo.ErrorWrap {
	var (
		lst    []*placeresp.RequestPlaceLogisticsModel
		count  int64
		limit  int = param.PageSize
		offset int = param.PageSize * (param.PageNo - 1)
	)

	db := global.Orm.Debug().Table("logistics l").Joins("left join places p on p.id = l.place_id")
	db.Select("l.*,p.place_name,p.user_name,p.hotel_id")

	if param.LoginUserId != 2 {
		userIdArr := NewUserDao().QueryChildUserIds(param.LoginUserId).Unwrap().([]int)
		placesIdArr := NewUserDao().GetPlacesIds(param.LoginUserId, userIdArr).Unwrap().([]int)
		db.Where("l.place_id in ?", placesIdArr)
	}

	if param.LogisticsOrderNo != "" {
		db.Where("l.logistics_order_no LIKE ?", "%"+param.LogisticsOrderNo+"%")
	}

	if param.PlaceStr != "" {
		PlaceStrSql := "%" + param.PlaceStr + "%"
		db.Where("(p.place_name LIKE ? OR p.id LIKE ?)", PlaceStrSql, PlaceStrSql)
	}

	if param.Status > 0 {
		db.Where("l.status=?", param.Status-1)
	}

	if param.ReturnStatus > 0 {
		db.Where("l.return_status=?", param.ReturnStatus)
	}

	db.Order("id DESC").Limit(limit).Offset(offset).Find(&lst).Limit(-1).Offset(-1).Count(&count)
	return dingo.ErrorIf(db.Error, lst, count)
}

// 根据状态查询网点
func (d *LogisticsDao) GetLogisticsStatusList() *dingo.ErrorWrap {
	var lst []*placemodel.PlaceLogisticsModel

	db := global.Orm.Debug().Table("logistics l")
	db.Where("status<>?", helper.TypeNumLogisticsStatusReceived)
	db.Where("status<?", helper.TypeNumLogisticsStatusSignOut)

	db.Find(&lst)
	return dingo.ErrorIf(db.Error, lst)
}

// 根据状态查询网点
func (d *LogisticsDao) GetLogisticsToStatusList(status uint8) *dingo.ErrorWrap {
	var lst []*placemodel.PlaceLogisticsModel

	db := global.Orm.Debug().Table("logistics").Where("status=?", status).Find(&lst)
	return dingo.ErrorIf(db.Error, lst)
}

// 根据网点ID查询物流信息
func (d *LogisticsDao) GetLogisticsInfoByPlaceId(placeId int) *dingo.ErrorWrap {
	m := placemodel.NewPlaceLogistics()

	db := global.Orm.Debug().Table("logistics").Where("place_id=? ORDER BY receive_time DESC ", placeId).Find(&m)
	return dingo.ErrorIf(db.Error, m)
}

func (d *LogisticsDao) GetLogisticsListByPlaceId(placeId int) *dingo.ErrorWrap {
	var lst []*placemodel.PlaceLogisticsModel

	db := global.Orm.Debug().Table("logistics").Where("place_id=? ORDER BY id DESC ", placeId).Find(&lst)
	return dingo.ErrorIf(db.Error, lst)
}

//查询所有网点签收时间
func (d *LogisticsDao) GetLogisticsReceiveTime(placeIds []int) *dingo.ErrorWrap {
	var list []*placeresp.PlaceIdReceiveTimeModel
	db := global.Orm.Debug().Table("logistics").Select("receive_time,place_id").Where("place_id in (?)", placeIds).Find(&list)
	return dingo.ErrorIf(db.Error, list)
}

//查询撤回门店列表
func (d *LogisticsDao) GetLogisticsReturnList(param *request.PlaceLogisticsModelListReq) *dingo.ErrorWrap {
	var (
		lst    []*placeresp.RequestPlaceLogisticsModel
		count  int64
		limit  int = param.PageSize
		offset int = param.PageSize * (param.PageNo - 1)
	)

	db := global.Orm.Debug().Table("logistics l").Joins("left join places p on p.id = l.place_id")
	db.Select("l.*,p.place_name,p.user_name,p.hotel_id")
	db.Where("l.return_status = 2")

	if param.IsAdmin != helper.TypeNumIsAdminOperator {
		userIdArr := NewUserDao().QueryChildUserIds(param.LoginUserId).Unwrap().([]int)
		placesIdArr := NewUserDao().GetPlacesIds(param.LoginUserId, userIdArr).Unwrap().([]int)
		db.Where("l.place_id in ?", placesIdArr)

	}

	if param.LogisticsOrderNo != "" {
		db.Where("l.logistics_order_no LIKE ?", "%"+param.LogisticsOrderNo+"%")
	}

	if param.PlaceStr != "" {
		PlaceStrSql := "%" + param.PlaceStr + "%"
		db.Where("(p.place_name LIKE ? OR p.id LIKE ?)", PlaceStrSql, PlaceStrSql)
	}

	if param.Status > 0 {
		db.Where("l.status=?", param.Status-1)
	}

	if param.ReturnStatus > 0 {
		db.Where("l.return_status=?", param.ReturnStatus)
	}

	db.Order("id DESC").Limit(limit).Offset(offset).Find(&lst).Limit(-1).Offset(-1).Count(&count)
	return dingo.ErrorIf(db.Error, lst, count)
}
